********************************************************************************
/* Reshape and prepare conjoint data

 - Clean and reshape data
 - Define attribute and levels as per design
 - Define matched attributes
	***DTA OUTPUT: final_cjoint.dta 
*/
********************************************************************************

clear
	clear matrix
	clear mata
	set more off
	set mem 5000m
	set maxvar 20000

cd "/Users/georgemelios/Downloads/PSRM_Replication 3"
use "DATA/cjoint_wide.dta", clear

*******************************************************************************
**# Clean and Reshape for Conjoint Analysis
*******************************************************************************

* Reshape

gen caseid = _n
ren set* choice*

reshape long choice, i(caseid) j(task)

replace choice = 0 if choice == 2

gen alti=1
sort caseid task alti, stable

* Expand

expand 2
replace choice = 2 if choice == 1 in 47889/95776
replace choice = 1 if choice == 0 in 47889/95776
replace choice = 0 if choice == 2 in 47889/95776
replace alti = 2 in 47889/95776

sort caseid task alti
egen case_count = seq(), by(caseid)

*******************************************************************************
**# Define the attribute and levels as they appear in the questionnaire
*******************************************************************************

** Race

gen cj_race = 0  /* set cj_race values to 0 (black) */

/* replace the values to 1 (if profile is white) */

replace cj_race = 1 if inlist(task, 2, 3, 8, 10, 11, 13, 14, 15, 16) & alt == 1
replace cj_race = 1 if inlist(task, 3, 6, 9, 11, 12, 15, 16) & alt == 2

//label cj_race
la define cj_race 1 "White" 0 "Black"
la val cj_race cj_race

** Party

gen cj_party = 0

/* replace the values to 1 (if profile is labour) */
replace cj_party = 1 if inlist(task, 1, 3, 4, 6, 10, 11, 13, 15) & alt == 1
replace cj_party = 1 if inlist(task, 1, 5, 6, 8, 10, 11, 13, 16) & alt == 2

//label cj_party
la define cj_party 1 "Labour" 0 "Tory"
la val cj_party cj_party

** Affect

gen cj_affect = 0

/* replace the values to 1 (open) */
replace cj_affect = 1 if inlist(task, 1, 2, 6, 10, 11, 12, 15) & alt == 1
replace cj_affect = 1 if inlist(task, 1, 3, 4, 8, 12, 14, 16) & alt == 2

//label cj_affect
la define cj_affect 1 "High" 0 "Low"
la val cj_affect cj_affect

** Education

gen cj_edu = 0

/* replace the values to 1 (degree) */
replace cj_edu = 1 if inlist(task, 3, 4, 6, 7, 14, 15, 16) & alt == 1
replace cj_edu = 1 if inlist(task, 1, 3, 4, 6, 7, 9, 13, 14, 16) & alt == 2

//label cj_edu
la define cj_edu 1 "Degree" 0 "No degree"
la val cj_edu cj_edu

** Beauty

gen cj_beauty = 0

/* replace the values to 1 (attractive) */

replace cj_beauty = 1 if inlist(task, 5, 6, 11, 13, 15) & alt == 1
replace cj_beauty = 1 if inlist(task, 1, 2, 3, 5, 6, 7, 9, 10, 12, 14, 15) & alt == 2

//label cj_beauty
la define cj_beauty 1 "Attractive" 0 "Unattractive"
la val cj_beauty cj_beauty

** Height

gen cj_height = 0

/* replace the values to 1 (tall) */

replace cj_height = 1 if inlist(task, 1, 2, 3, 4, 8, 9, 10, 13, 15, 16) & alt == 1
replace cj_height = 1 if inlist(task, 1, 2, 3, 7, 10, 14) & alt == 2

//label cj_height
la define cj_height 1 "Tall" 0 "Short"
la val cj_height cj_height

** Diet

gen cj_diet = 0

/* replace the values to 1 (veg) */

replace cj_diet = 1 if inlist(task, 4, 9, 10, 12, 14, 15, 16) & alt == 1
replace cj_diet = 1 if inlist(task, 2, 3, 5, 6, 8, 10, 14, 15, 16) & alt == 2

//label cj_diet
la define cj_diet 1 "Veg" 0 "None"
la val cj_diet cj_diet

** Ideology

gen cj_ideology = 0

/* replace the values to 1 (progressive) */

replace cj_ideology = 1 if inlist(task, 1, 2, 3, 5, 6, 7, 14, 15, 16) & alt == 1
replace cj_ideology = 1 if inlist(task, 2, 5, 10, 11, 12, 14, 16) & alt == 2

//label cj_ideology
la define cj_ideology 1 "Progressive" 0 "Traditional"
la val cj_ideology cj_ideology

*******************************************************************************
**# Generate matched attributes
*******************************************************************************

* Race

gen cj_matchrace = 0
replace cj_matchrace = 1 if white == 1 & cj_race == 1 //white respondent-white profile
replace cj_matchrace = 1 if black == 1 & cj_race == 0 //black respondent-black profile
replace cj_matchrace = . if ethnic == . // no need to drop nonblack and nonwhite // matchrace = 0 will correspond to out-group either way
replace cj_matchrace = . if ethnic == 99

* Party

gen cj_matchpid = 0
replace cj_matchpid = 1 if party_id == 1 & cj_party == 1 //labour respondent-labour profile
replace cj_matchpid = 1 if party_id == 2 & cj_party == 0 //tory respondent-tory profile
replace cj_matchpid = . if party_id == 3 // remove independents so that matchpid is binary variable for in-party and out-party

* Affect

//define: polarized=rating_like(in_party) - rating_like(out_party)
gen polarized = labour_like - tory_like
replace polarized = -1*polarized if polarized < 0

//define: high polarization-tolerance low; low polarization-tolerance high
sum pol,d //(mean is 3.6 -> use 4 as discreet cutoff)

gen cj_matchaff = 0
replace cj_matchaff = 1 if pol < 5 & cj_affect == 1 //not polarized - tolerant profile
replace cj_matchaff = 1 if pol > 4 & cj_affect == 0 //polarized respondent - intolerant profile
replace cj_matchaff = . if pol == .

* Education

gen cj_matched = 0
replace cj_matched = 1 if degree == 1 & cj_edu == 1 //respondent with degree - profile with degree
replace cj_matched = 1 if degree == 0 & cj_edu == 0 //respondent without degree - profile without degree
replace cj_matched = . if degree ==.


* Education 

/*
profile is more or equally educated than respondent (1)
profile is less educated than respondent (0)
*/

gen more_educated = .  
replace more_educated = 1 if degree == 0 & cj_edu == 1 //profile more educated than respondent
replace more_educated = 0 if degree == 1 & cj_edu == 0 //profile less educated than respondent

la define more_educated 1 "Profile more educated" 0 "Profile less educated"
la val more_educated more_educated

* Beauty

gen cj_matchbeau = 0
replace cj_matchbeau = 1 if beauty_short == 1 & cj_beauty == 1 //respondent attractive - profile attractive
replace cj_matchbeau = 1 if beauty_short == 0 & cj_beauty == 0 //respondent unattractive - profile unattractive
replace cj_matchbeau = . if beauty_short ==.

* Height

xtile height_m_5 = height if which_set == 1, n(5) //those who rated men
xtile height_w_5 = height if which_set == 2, n(5) //those who rated women

gen cj_matchhei2 = 0

replace cj_matchhei2 = 1 if height_m_5 == 4 & cj_height == 0 & which_set == 1 //short
replace cj_matchhei2 = 2 if height_m_5 == 5 & cj_height == 1 & which_set == 1 //tall

replace cj_matchhei2 = 1 if height_w_5 == 1 & cj_height == 0 & which_set == 2 //short
replace cj_matchhei2 = 2 if height_w_5 == 2 & cj_height == 1 & which_set == 2 //tall

replace cj_matchhei2 = . if height == .

la define cj_matchhei2 0 "No match" 1 "Short" 2 "Tall"
la val cj_matchhei2 cj_matchhei2

recode cj_matchhei2 ///
(0=0 "No match") ///
(1/2 = 1 "Matched height") ///
(else=.), gen (cj_matchhei)

* Height for gender test

gen cj_heighgend = 0

//respondent is taller than male profile 
replace cj_heighgend = 1 if cj_height == 1 & height > 183 & which_set == 1
replace cj_heighgend = 1 if cj_height == 0 & height > 173 & which_set == 1

//respondent is shorter than male profile 
replace cj_heighgend = 2 if cj_height == 1 & height < 183 & which_set == 1
replace cj_heighgend = 2 if cj_height == 0 & height < 173 & which_set == 1

//respondent is the same height as male profile
replace cj_heighgend = 0 if cj_height == 1 & round(height, 0.01) == 182.88 & which_set == 1
replace cj_heighgend = 0 if cj_height == 0 & round(height, 0.01) == 172.72 & which_set == 1
///////////////////////////////////////////////////////////////////////////////
//respondent is taller than female profile
replace cj_heighgend = 1 if cj_height == 1 & height > 173 & which_set == 2
replace cj_heighgend = 1 if cj_height == 0 & height > 163 & which_set == 2

//respondent is shorter than female profile
replace cj_heighgend = 2 if cj_height == 1 & height < 173 & which_set == 2
replace cj_heighgend = 2 if cj_height == 0 & height < 163 & which_set == 2

//respondent is the same height as female profile
replace cj_heighgend = 0 if cj_height == 1 & round(height, 0.01) == 172.72 & which_set == 2
replace cj_heighgend = 0 if cj_height == 0 & round(height, 0.01) == 162.56 & which_set == 2

replace cj_heighgend = . if height ==. 

//recode to binary
recode cj_heighgend ///
(1=0 "Shorter profile") ///
(2=1 "Taller profile") ///
(else=.), gen (shorter_taller)

//label 
la define cj_heighgend 1 "Shorter profile" 2 "Taller profile" 0 "Same height"
la val cj_heighgend cj_heighgend

* Diet

gen cj_matchdiet = 0
replace cj_matchdiet = 1 if diet_short == 1 & cj_diet == 1 //respondent veg - profile veg
replace cj_matchdiet = 1 if diet_short == 0 & cj_diet == 0 //respondent nonveg - profile nonveg

replace cj_matchdiet = . if diet_short ==.

* Ideology 

gen cj_matchid = 0
replace cj_matchid = 1 if right_left == 3 & cj_ideology == 1 //respondent left - profile progressive
replace cj_matchid = 1 if right_left == 1 & cj_ideology == 0 //respondent right - profile traditional

replace cj_matchid = . if right_left == 2 //remove moderates as in party id
replace cj_matchid = . if right_left == .

*******************************************************************************
* More specific matches
*******************************************************************************

//race
gen cj_matchrace2 = cj_matchrace
replace cj_matchrace2 = 2 if white == 1 & cj_race == 1
la define cj_matchrace2 0 "No match" 1 "Black" 2 "White"
la val cj_matchrace2 cj_matchrace2

//party 
gen cj_matchpid2 = cj_matchpid
replace cj_matchpid2 = 2 if party_id == 1 & cj_party  == 1
la define cj_matchpid2 0 "No match" 1 "Tory" 2 "Labour"
la val cj_matchpid2 cj_matchpid2

//education
gen cj_matched2 = cj_matched 
replace cj_matched2 = 2 if degree == 1 & cj_edu == 1
la define cj_matched2 0 "No match" 1 "No degree" 2 "Degree"
la val cj_matched2 cj_matched2

//ideology
gen cj_matchid2 = cj_matchid
replace cj_matchid2 = 2 if right_left == 3 & cj_ideology == 1 //left
la define cj_matchid2 0 "No match" 1 "Traditional" 2 "Progressive"
la val cj_matchid2 cj_matchid2

//diet
gen cj_matchdiet2 = cj_matchdiet
replace cj_matchdiet2 = 2 if diet_short == 1 & cj_diet == 1 //veg
la define cj_matchdiet2 0 "No match" 1 "Non-veg" 2 "Veg"
la val cj_matchdiet2 cj_matchdiet2

//beauty
gen cj_matchbeau2 = cj_matchbeau
replace cj_matchbeau2 = 2 if beauty_short == 1 & cj_beauty == 1 //beautiful
la define cj_matchbeau2 0 "No match" 1 "Low" 2 "High"
la val cj_matchbeau2 cj_matchbeau2

//tolerance
gen cj_matchaff2 = cj_matchaff
replace cj_matchaff2 = 2 if pol < 5 & cj_affect == 1 //tolerant
la define cj_matchaff2 0 "No match" 1 "Intolerant" 2 "Tolerant"
la val cj_matchaff2 cj_matchaff2

//height: done, cj_matchhei2

*******************************************************************************
**# Extra cleaning for analysis
*******************************************************************************

//Attribute value labels
la define cj_matchpid 1 "In-party" 0 "Out-party"
la val cj_matchpid cj_matchpid
la define cj_affect 1 "Tolerant" 0 "Intolerant", modify

//relationship
recode rel_short (1=1) (2=0)

//independents
ta party_id, gen (party_id)
ren party_id3 Independent
drop party_id2 party_id1

//strong partisans
gen extreme_partisans = 0
replace extreme_partisans = 1 if polarized > 5
replace extreme_partisans = . if Independent == 1
ta extreme_partisans

//survey round
gen round = .
replace round = 0 if date(startdate, "YMDhms") >= date("2023-07-01", "YMD") & date(startdate, "YMDhms") < date("2023-07-03", "YMD")
replace round = 1 if date(startdate, "YMDhms") >= date("2023-07-03", "YMD") & date(startdate, "YMDhms") < date("2023-07-06", "YMD")
replace round = 2 if date(startdate, "YMDhms") >= date("2023-07-06", "YMD")

//sex recode based on cjoint tasks
gen sex = .
replace sex = 1 if male_female == 1 & which_set == 2 //men rating women
replace sex = 0 if male_female == 0 & which_set == 1  //women rating men
la define sex 1 "Men" 0 "Women"
la val sex sex

//tolerance x partisan match
gen cj_matchaff3 =  cj_matchaff2
replace cj_matchaff3 = 1 if cj_matchaff2 == 1 & cj_matchpid == 1 //intolerant in-party
replace cj_matchaff3 = 2 if cj_matchaff2 == 2 & cj_matchpid == 1 //tolerant in-party

replace cj_matchaff3 = 3 if cj_matchaff2 == 1 & cj_matchpid == 0 //intolerant out-party
replace cj_matchaff3 = 4 if cj_matchaff2 == 2 & cj_matchpid == 0 //tolerant out-party

la define cj_matchaff3 1 "In-party;Intolerant" 2 "In-party;Tolerant" 3 "Out-party;Intolerant" 4 "Out-party;Tolerant"
la val cj_matchaff3 cj_matchaff3

//alternative tolerance measure using party feeling thermometers

gen polarized2 = labour_therm - tory_therm
replace polarized2 = -1*polarized2 if polarized2 < 0

//define: high polarization-tolerance low; low polarization-tolerance high
sum polarized2,d //(mean is 4.5 -> use 5 as discreet cutoff)

gen cj_matchaff_rob = 0
replace cj_matchaff_rob = 1 if polarized2 < 6 & cj_affect == 1 //not polarized - tolerant profile
replace cj_matchaff_rob = 1 if polarized2 > 5 & cj_affect == 0 //polarized respondent - intolerant profile
replace cj_matchaff_rob = . if polarized2 == .

save "DATA/final_cjoint.dta", replace
